#include <iostream>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include "unitvector.hpp"

#define HEATBEAT	0x00
#define LOGIN		0x01
#define LOGOUT		0x02
#define GPEERLIST	0x03

#define SUCCESS		0x00
#define FAILED		0xff
#define LOGINED		0x01
#define LOGOUTD		0x02
#define BUSY		0x03
#define IDLE		0x04

using namespace std;
UnitVector			PeerList;
UnitVector::Node	gTmpNode;
int port=2010;

unsigned char ChkPackeg(unsigned char *buf,int len);
unsigned char CutCrc(unsigned char *buf,int len);
int main()
{
	unsigned char	message[256];
	unsigned char	buf[512];
	unsigned char	cmd=0x00;
	unsigned short	revlen=0;
	int socket_descriptor;
	struct sockaddr_in sin;
	struct sockaddr_in clientInfo;
	socklen_t sin_len;
	int addr_len =sizeof(struct sockaddr_in);

	printf("Server is starting...\n");

	bzero(&sin,sizeof(sin));
	bzero(&clientInfo,sizeof(clientInfo));
	bzero(buf,512);

	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = htonl(INADDR_ANY);
	sin.sin_port = htons(port);
	socket_descriptor = socket(AF_INET,SOCK_DGRAM,0);
	bind(socket_descriptor,(struct sockaddr *)&sin,sizeof(sin));
	while(1)
	{
		bzero(&message,sizeof(message));
		revlen = recvfrom(socket_descriptor,message,sizeof(message),0,(struct sockaddr*)&sin,&sin_len);
		if(revlen == 0xffff)
		{
			printf("Recv a Error Data!\n");
			continue;
		}
		memcpy(&clientInfo,&sin,sizeof(sin));
		if(strncmp((char *)message,"stop",4) == 0)
		{
			printf("Server is end Now!\n");
			break;
		}
		else if(clientInfo.sin_port == 0)
		{
			printf("Addr is Error!\n");
		continue;
		}

		//检查包格式是否正确
		if(ChkPackeg(message,revlen) == 0xff)
		{//格式不对，就返回主循环；
			printf("Check Packeg Error!\n");
			continue;
		}
		cmd=message[6];
		switch(cmd)
		{
			case	HEATBEAT:
			{
				printf("Heart bit Packeg Got.\n");
			}
			break;
			case	LOGIN:
			{
				memset(&gTmpNode,0x00,sizeof(UnitVector::Node));
				memcpy(gTmpNode.Id,message,6);
				memcpy(&gTmpNode.ClientAddr,&clientInfo,sizeof(clientInfo));
				memcpy(buf,message,6);
				buf[6] = LOGIN;
				buf[7] = 0x01;
				buf[8] = 0x00;
				//检查是否已经登陆
				//11 11 11 11 11 11| LOGIN | 数据长度 | SUCCESS | SUM CRC
				if(PeerList.Add(gTmpNode) == -1)
				{//如果未登陆，就登陆,返回登陆OK
					buf[9] = SUCCESS;
					printf("Login Success!\n");
				}
				else
				{//否则返回已经登陆
					buf[9] = LOGINED;
					printf("Logined!\n");
				}
				buf[10]=CutCrc(buf,10);
				sendto(socket_descriptor,buf,11,0,(struct sockaddr *)&clientInfo,addr_len);
			}
			break;
			case	LOGOUT:
			{
				memcpy(gTmpNode.Id,message,6);
				memcpy(&gTmpNode.ClientAddr,&clientInfo,sizeof(clientInfo));
				memcpy(buf,message,6);
				buf[6] = LOGIN;
				buf[7] = 0x01;
				buf[8] = 0x00;
				//检查是否已经退出
				//11 11 11 11 11 11| LOGIN | 数据长度 | SUCCESS | SUM CRC
				if(PeerList.DelNode(&gTmpNode) == true)
				{//如果删除成功，返回SUCCESS
					buf[9] = SUCCESS;
					printf("Logout success.\n");
				}
				else
				{//否则返回已经登出
					buf[9] = LOGOUTD;
					printf("Logouted.\n");
				}
				buf[10]=CutCrc(buf,10);
				sendto(socket_descriptor,buf,11,0,(struct sockaddr *)&clientInfo,addr_len);
			}
			break;
			case    GPEERLIST:
			{//得到PEER列表
				int len=0;
				unsigned short Nodelen=sizeof(gTmpNode);
				unsigned char *pbuf=buf;
				bzero(pbuf,sizeof(512));
				memcpy(pbuf,message,6);
				//得到PEER列表的长度
				pbuf += 6;
				*pbuf = GPEERLIST;
				pbuf++;
				*pbuf = Nodelen;
				pbuf++;
				*pbuf = (Nodelen>>8)&0x00ff;
				pbuf++;
				len = PeerList.GetPeerNum();
				for(int i=0;i<len;i++)
				{
					if(PeerList.GetPeerList(i,&gTmpNode) == false)
					{
						break;
					}
					else
					{
						memcpy(pbuf,&gTmpNode,sizeof(gTmpNode));
					}
						sendto(socket_descriptor,buf,sizeof(gTmpNode),0,(struct sockaddr *)&clientInfo,addr_len);
					}
					//循环发送回请求端
			}
            break;
			default:
				printf("Error Packeg form:%s\n",inet_ntoa(clientInfo.sin_addr));
			break;
		}
//		sleep(1);
	}
	close(socket_descriptor);
	return 0;
}
unsigned char ChkPackeg(unsigned char *buf,int len)
{
	unsigned short i=0;
	unsigned short	Pkgend=len-1;
	unsigned char PkgChkVal=0x00;
	unsigned char t=0x00;
	for(i=0;i<Pkgend;i++)
	{
		t=t+buf[i];
	}
	PkgChkVal=buf[Pkgend];
	if(t == PkgChkVal)
	{
		t=0x00;
	}
	else
	{
		t=0xff;
	}
	return t;
}
unsigned char CutCrc(unsigned char *buf,int len)
{
	unsigned char val=0x00;
	for(int i=0;i<len;i++)
	{
		val+=buf[i];
	}
	return val;
}


